package com.cxs.videoplayer.player;

import com.cxs.videoplayer.ResourceTable;
import com.cxs.videoplayer.constant.ControllCode;
import com.cxs.videoplayer.data.PlayInfo;
import com.cxs.videoplayer.data.VideoInfo;
import com.cxs.videoplayer.util.PixelUtils;
import ohos.agp.components.Component;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.DragInfo;
import ohos.agp.components.ProgressBar;
import ohos.agp.components.surfaceprovider.SurfaceProvider;
import ohos.agp.graphics.Surface;
import ohos.agp.graphics.SurfaceOps;
import ohos.agp.utils.Point;
import ohos.agp.window.service.WindowManager;
import ohos.app.Context;
import ohos.app.dispatcher.TaskDispatcher;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.global.resource.RawFileDescriptor;
import ohos.media.common.Source;
import ohos.media.player.Player;
import ohos.multimodalinput.event.MmiPoint;
import ohos.multimodalinput.event.TouchEvent;

import java.io.IOException;
import java.util.List;

public class HmPlayer implements IHmPlayer{

    private Context context;
    private SurfaceProvider surfaceProvider;
    private Player player = null;
    List<VideoInfo> videoInfoList;
    private VideoInfo videoInfo;
    private boolean isPlaying = false;
    private Surface surface = null;
    private ControllCode status = null;
    private final static int EVENT_ID = 0;
    private final static long MICRO_MILLI_RATE = 1000;
    private final static long START_MILLI_TIME = 0;
    private static long CURRENT_MILLI_TIME = 0;
    TaskDispatcher mainTask;
    private DirectionalLayout controllView;
    private ProgressBar progressBar;


    SurfaceOps.Callback surfaceCallback = new SurfaceOps.Callback() {
        @Override
        public void surfaceCreated(SurfaceOps surfaceOps) {
            surface = surfaceOps.getSurface();
            start(CURRENT_MILLI_TIME);
        }

        @Override
        public void surfaceChanged(SurfaceOps surfaceOps, int i, int i1, int i2) { }

        @Override
        public void surfaceDestroyed(SurfaceOps surfaceOps) { }
    };

    EventHandler eventHandler = new EventHandler(EventRunner.create()) {
        @Override
        protected void processEvent(InnerEvent event) {
            super.processEvent(event);
            if (event == null) {
                return;
            }
            status = (ControllCode)event.object;
            switch (status) {
                case START:
                    player.setVideoSurface(surface);
                    prepare();
                    rewindTo(CURRENT_MILLI_TIME);
                    play();
                    mainTask.asyncDispatch(() -> {
                        progressBar.setMaxValue((int)getDuration());
                    });
                    break;
                case PLAY:
                    play();
                    break;
                case PLAYING:
                    mainTask.asyncDispatch(() -> {
                        isPlaying = true;
                        progressBar.setProgressValue((int)getCurrentTime());
                    });
                    eventHandler.sendEvent(InnerEvent.get(EVENT_ID, ControllCode.PLAYING), MICRO_MILLI_RATE);
                    break;
                case PAUSE:
                    isPlaying = false;
                    pause();
                    break;
            }

        }
    };


    public HmPlayer(Context context) {
        this.context = context;
        player = new Player(context);

        mainTask = context.getUITaskDispatcher();
    }

    public SurfaceProvider getSurfaceProvider() {
        surfaceProvider = new SurfaceProvider(context);
        surfaceProvider.getSurfaceOps().get().addCallback(surfaceCallback);
        surfaceProvider.setHeight(PixelUtils.vp2px(context, 200));
        surfaceProvider.pinToZTop(false);
        WindowManager.getInstance().getTopWindow().get().setTransparent(true);
        return surfaceProvider;
    }

    public void execute(PlayInfo playInfo) {
        VideoInfo videoInfo = playInfo.getVideoInfo();
        long currentTime = playInfo.getCurrentTime();
        CURRENT_MILLI_TIME = currentTime;
        setVideo(videoInfo);
    }

    public void setVideoView(DirectionalLayout controllView) {
        this.controllView = controllView;
        progressBar = (ProgressBar) controllView.findComponentById(ResourceTable.Id_video_progress_bar);

        initListener();
    }

   private MmiPoint start;
    private void initListener() {
        surfaceProvider.setClickedListener(component -> {
            if (isPlaying) {
                pause();
            } else {
                play();
            }
        });
        // 滑动切换
        surfaceProvider.setTouchEventListener(new Component.TouchEventListener() {
            @Override
            public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
                MmiPoint point = touchEvent.getPointerPosition(0);
                int action = touchEvent.getAction();
                switch (action) {
                    case TouchEvent.PRIMARY_POINT_DOWN: {
                        start = point;
                        return true;
                    }
                    case TouchEvent.PRIMARY_POINT_UP: {
                        nextVideoPlay(getSlideState(start, point));
                        return true;
                    }
                }
                return true;
            }
        });
    }

    // 滑动切换视频
    private boolean nextVideoPlay(SlideState slideState) {
        if (videoInfoList == null || videoInfoList.size() <= 0) {
            return false;
        }
        int total = videoInfoList.size();
        int index = videoInfo == null ? 0 : videoInfo.getIndex();  // 当前视频在列表中的索引
        switch (slideState) {
            case LEFT:
                // 左滑
                index++;
                if (index >= total) {
                    index = 0;
                }
                setVideo(videoInfoList.get(index));
                start(START_MILLI_TIME);
                return true;
            case RIGHT:
                // 右滑
                index--;
                if (index < 0) {
                    index = total - 1;
                }
                setVideo(videoInfoList.get(index));
                start(START_MILLI_TIME);
                return true;
        }
        return false;
    }


    @Override
    public void setSurface(Surface surface) {
        this.surface = surface;
    }

    /**
     * 设置视频源
     * @param videoInfo
     */
    @Override
    public void setVideo(VideoInfo videoInfo) {
        if (videoInfo == null) {
            return;
        }
        this.videoInfo = videoInfo;
        String url = videoInfo.getUrl();
        if (url == null || url.equals("")) {
            return;
        }
        if (player != null) {
            release();
        }
        player = new Player(context);
        RawFileDescriptor fd = null;
        try {
            fd = context.getResourceManager().getRawFileEntry(url).openRawFileDescriptor();
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        // 构造数据源对象
        Source source = new Source(fd.getFileDescriptor(), fd.getStartPosition(), fd.getFileSize());
        // 设置媒体源
        player.setSource(source);
        // 设置Player的回调函数
        player.setPlayerCallback(playerCallback);
    }

    @Override
    public void start(long position) {
        CURRENT_MILLI_TIME = position;
        eventHandler.sendEvent(InnerEvent.get(EVENT_ID, ControllCode.START));
    }

    @Override
    public boolean prepare() {
        if (player == null) {
            return false;
        }
        return player.prepare();
    }

    @Override
    public void play() {
        if (player == null) {
            return;
        }
        player.play();
        eventHandler.sendEvent(InnerEvent.get(EVENT_ID, ControllCode.PLAYING), MICRO_MILLI_RATE);
    }


    @Override
    public void pause() {
        if (player == null) {
            return;
        }
        isPlaying = false;
        player.pause();
        eventHandler.removeAllEvent();
    }

    @Override
    public void stop() {
        isPlaying = false;
        player.stop();

    }

    @Override
    public void release() {
        if (player == null) {
            return;
        }
        isPlaying = false;
        player.release();
        player = null;
        eventHandler.removeAllEvent();
    }

    @Override
    public long getDuration() {
        return player.getDuration();
    }

    @Override
    public void rewindTo(long currentTime) {
        player.rewindTo(currentTime);
    }

    @Override
    public long getCurrentTime() {
        return player.getCurrentTime();
    }

    public VideoInfo getVideoInfo() {
        return videoInfo;
    }

    @Override
    public void setVideoList(List<VideoInfo> videoInfoList) {
        this.videoInfoList = videoInfoList;
    }

    public ControllCode getStatus() {
        return status;
    }

    Player.IPlayerCallback playerCallback = new Player.IPlayerCallback() {
        @Override
        public void onPrepared() {
        }

        @Override
        public void onMessage(int i, int i1) {

        }

        @Override
        public void onError(int i, int i1) {
            System.out.println("onError");
            eventHandler.removeAllEvent();
        }

        @Override
        public void onResolutionChanged(int i, int i1) {

        }

        @Override
        public void onPlayBackComplete() {
            eventHandler.removeAllEvent();
        }

        @Override
        public void onRewindToComplete() {

        }

        @Override
        public void onBufferingChange(int i) {

        }

        @Override
        public void onNewTimedMetaData(Player.MediaTimedMetaData mediaTimedMetaData) {

        }

        @Override
        public void onMediaTimeIncontinuity(Player.MediaTimeInfo mediaTimeInfo) {

        }
    };

    /**
     * 左滑或右滑
     * @return
     */
    private SlideState getSlideState(MmiPoint start, MmiPoint end) {
        float startX = start.getX();
        float startY = start.getY();
        float endX = end.getX();
        float endY = end.getY();
        if (endX > startX && Math.abs(endY - startY) < 100) {
            return SlideState.RIGHT;
        } else if (endX < startX && Math.abs(endY - startY) < 100) {
            return SlideState.LEFT;
        }
        return SlideState.NULL;
    }

    enum SlideState {
        // 左滑
        LEFT(0),
        // 右滑
        RIGHT(1),

        NULL(-1);

        private final int code;
        SlideState(int value) {
            this.code = value;
        }

        public int getCode() {
            return code;
        }
    }

}
